package com.wang.template.json;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import com.wang.template.json.asm.MethodAccess;
import com.wang.template.json.core.Keys;
import com.wang.template.json.core.MethodCache;
import com.wang.template.json.express.BaseExpress;
import com.wang.template.json.express.ListExpress;
import com.wang.template.json.express.MapExpress;
import com.wang.template.json.express.StaticExpress;
import com.wang.template.json.node.ArrayNode;
import com.wang.template.json.node.BaseNode;
import com.wang.template.json.node.DataSource;
import com.wang.template.json.node.ObjectNode;
import com.wang.template.json.util.UtilExt;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class JsonRender {
	private static Map<String, MethodAccess> methodCache = MethodCache.getInstance().getMethodCache();

	public static Object render(BaseNode node, Object dataSource) {
		switch (node.getType()) {
			case STRING: {
				return getValueByNode(node, dataSource);
			}case OBJECT: {
				return getObjectNodeData((ObjectNode) node, dataSource);
			}case ARRAY: {
				return getArrayNodeData((ArrayNode) node, dataSource);
			}default: {
				return null;
			}
		}
	}

	private static Object getObjectNodeData(ObjectNode node, Object dataSource) {
		if (node.getDs() != null) {
			// 如果指明了数据源那么用指定的数据源
			dataSource = getValueByNode(node, dataSource);
		}
		Map<String, BaseNode> map = node.getMap();
		if (map == null) {
			// 对象没有设置映射关系，则找到深度key对应的值
			return dataSource;
		} else {
			Map<String, Object> result = new HashMap<String, Object>(map.size());
			for (Entry<String, BaseNode> entity : map.entrySet()) {
				Object propertyValue = render(entity.getValue(), dataSource);
				result.put(entity.getKey(), propertyValue);
			}
			return result;
		}
	}

	/**
	 * 获取array类型节点的数据
	 */
	private static Object getArrayNodeData(ArrayNode arryNode, Object dataSource) {
		List<Object> dataList = (List<Object>) getValueByNode(arryNode, dataSource);
		if (dataList == null) {
			return null;
		}
		Map<String, BaseNode> map = arryNode.getMap();
		if (map == null) {
			return dataList;
		}
		List<Object> list = new LinkedList<Object>();
		Map<String, Object> innerDs = getArrayDs(dataSource);

		for (Object indexData : dataList) {
			innerDs.put(Keys.NODE_KEY_INDEX, indexData);
			// 单行数据解析使用的数据源
			Map<String, Object> row = new HashMap<String, Object>(map.size());
			for (Entry<String, BaseNode> entity : map.entrySet()) {
				BaseNode node = entity.getValue();
				Object propertyvalue = render(node, innerDs);
				row.put(entity.getKey(), propertyvalue);
			}
			list.add(row);
		}
		if (innerDs == dataSource) {
			innerDs.put(Keys.NODE_KEY_INDEX, innerDs.get(Keys.NODE_KEY_SUPER));
		}
		return list;
	}

	/**
	 * 设置arry的数据源<br>
	 * 为了能获取上一级的数据<br>
	 * 
	 * @return
	 */
	private static Map<String, Object> getArrayDs(Object ds) {
		if (ds instanceof Map) {
			Map<String, Object> innerDs = (Map<String, Object>) ds;
			Object superObject = innerDs.get(Keys.NODE_KEY_INDEX);
			if (superObject == null) {
				innerDs.put(Keys.NODE_KEY_SUPER, ds);
			} else {
				innerDs.put(Keys.NODE_KEY_SUPER, superObject);
			}
			return innerDs;
		} else {
			Map<String, Object> innerDs = new HashMap<String, Object>();
			innerDs.put(Keys.NODE_KEY_SUPER, ds);
			return innerDs;
		}

	}

	/**
	 * 获取一个表达式对应的值<br>
	 * 表达式可能是个深度表达式，需要一个个解析
	 * 
	 * @param node
	 * @param data
	 * @return
	 */
	private static Object getValueByNode(BaseNode node, Object data) {
		if (data == null) {
			return null;
		}
		DataSource ds = node.getDs();
		if (ds.isDeep()) {
			// 如果是深度访问
			BaseExpress[] expressArray = ds.getExpress();
			BaseExpress express = null;
			for (int index = 0, deep = ds.getExpress().length; index < deep; index++) {
				if (data == null) {
					break;
				}
				express = expressArray[index];
				data = getValueByExpress(data, express);
			}
			return data;
		} else {
			return getValueByExpress(data, ds.getExpress()[0]);
		}
	}

	/**
	 * 获取一个表达式对应的值
	 * 
	 * @param object
	 * @param ex
	 * @return
	 */
	private static Object getValueByExpress(Object object, BaseExpress ex) {
		if (object instanceof Map) {
			object = ((Map<String, Object>) object).get(ex.getDs());
		} else {
			object = getObjectValueByMethodName(object, ex);
		}
		if (object == null) {
			return null;
		}
		switch (ex.getExpressType()) {
		case STATIC: {
			return ((StaticExpress) ex).getStaticValue();
		}
		case STRING: {
			return object;
		}
		case MAP: {
			MapExpress me = (MapExpress) ex;
			Map<String, Object> map = (Map<String, Object>) object;
			return map.get(me.getKey());
		}
		case LIST: {
			ListExpress le = (ListExpress) ex;
			if (object instanceof List) {
				return ((List<Object>) object).get(le.getIndex());
			} else if (object instanceof Object[]) {
				return ((Object[]) object)[le.getIndex()];
			} else {
				throw new RuntimeException(
						String.format("表达式是map类型%s，但是实际数据源不是map:%s", ex.toString(), object.toString()));
			}
		}
		}
		return null;
	}

	private static Object getObjectValueByMethodName(Object object, BaseExpress ex) {
		Class c = object.getClass();
		String className = c.getName();
		MethodAccess methodInfo = methodCache.get(className);
		if (methodInfo == null) {
			try {
				UtilExt.addMethodAccess(c);
			} catch (Exception e) {
				e.printStackTrace();
			}
			methodInfo = methodCache.get(className);
		}
		return methodInfo.invoke(object, ex.getDsMethodName());
	}
}
